<?php

namespace Category;

use W3\Util;
use Base\Metas;


/**
 * 分类输出组件
 *
 * @author edikud
 * @date 2022/10/22
 * @copyright Copyright (c) 2022 W3 (http://www.mcooo.com)
 * @license GNU General Public License 2.0
 */
class Rows extends Metas
{
    /**
     * 所有分类哈希表 
     * 
     * @var array
     * @access private
     */
    private $_map = [];
	
    /**
     * 初始化
     *
     * @access protected
     * @return void
     */
    protected function init()
    {
		# 定义变量默认数据
        $this->parameter([
			
			# 忽略某个分类(注意：包括子分类)
		    'ignore' => 0		
			
		], true);
	}
	
    public function execute()
    {
        /** 按category查询 */
        $categories = $this->db
			->select()
		    ->from('table.metas')
			->where('table.metas.type = ?', 'category')
			->limit(10000)
			->order('table.metas.order', 'ASC')
			->get();
			
	    $this->_map = Util::arrayTree($categories, 'mid', 'parent');
		
		# ignore 忽略某个分类 (注意：包括子分类)
        if ($this->parameter->ignore) {
			$ignore = explode(',', $this->parameter->ignore);
			$list = [];
            foreach ($ignore as $mid) 
			{
                if (isset($this->_map[$mid])) {
					$list += $this->getAllChildren($mid);
                }
            }
			if ($list) {
                foreach ($list as $val) {
					unset($this->_map[$val['mid']]);
                }
				$this->_map = Util::arrayTree(array_values($this->_map), 'mid', 'parent');
			}
        }
		
		$this->_map = array_map([$this, 'push'], $this->_map);
    }
	
    # 获取某个分类所有直系父级节点mid (包括自己)
    public function getParentsMids(int $mid) : array
    {
        $result = [];
        if (!isset($this->_map[$mid])) {
            return $result;
        }
        $parent = $mid;
        while ($parent) {
            $result[] = $parent;
            $parent = $this->_map[$parent]['parent'];
        }
        $result && ($result = array_reverse($result));

        return $result;
    }
	
    /**
     * 获取某个分类所有直系父级节点缩略名 (包括自己)
     * 
     * @param mixed $mid 
     * @access public
     * @return array
     */
    public function getParentsAlias(int $mid) : array
    {
        $result = [];
        if (!isset($this->_map[$mid])) {
            return $result;
        }
        $parent = $mid;
        while ($parent) {
            $result[] = $this->_map[$parent]['alias'];
            $parent = $this->_map[$parent]['parent'];
        }
        $result && ($result = array_reverse($result));

        return $result;
    }
    /**
     * 获取某个分类所有直系父级节点 (包括自己)
     * 
     * @param mixed $mid 
     * @access public
     * @return array
     */
    public function getParents(int $mid) : array
    {
        $result = [];
        if (!isset($this->_map[$mid])) {
            return $result;
        }
        $parent = $mid;
        while ($parent) {
            $result[$parent] = $this->_map[$parent];
            $parent = $this->_map[$parent]['parent'];
        }
        $result && ($result = array_reverse($result));

        return $result;
    }
	
    /**
     * 获取某个分类所有父级节点
     * 
     * @param mixed $mid 
     * @access public
     * @return array
     */
    public function getAllParents(int $mid) : array
    {
		$result = [];
		
		if (!$mid) 
			return $result;
		
        $category_direct = $this->getParentsMids($mid);
		
		if (!$category_direct) 
			return $result;
		
        $level = count($category_direct) - 1;
        $parent = $category_direct[0];
		
        if ($level == 1) {
            return $this->_map[$parent];
        }
		
        $list = $this->getAllChildren($parent);
        
        foreach ($list as $category) 
		{
            if ($category['level'] < $level) {
                $result[$category['mid']] = $category;
            }
        }
        return $result;
    }
	
    /**
     * 获取某个分类下的所有子节点(包括自己)
     * 
     * @param mixed $mid 
     * @access public
     * @return array
     */
    public function getAllChildren(int $mid) : array
    {
        $result = [];

        if (!isset($this->_map[$mid])) {
            return $result;
        }
        $result = array_slice($this->_map, $this->_map[$mid]['offset'], $this->_map[$mid]['num'], true);
		
        return $result;
    }

    /**
     * 获取单个分类
     * 
     * @param integer $mid 
     * @access public
     * @return mixed
     */
    public function get(int $mid)
    {
        return $this->_map[$mid] ?? NULL;
    }

    /**
     * 获取多个分类 
     * 
     * @param mixed $mids 
     * @access public
     * @return array
     */
    public function export() : array
    {
        return $this->_map;
    }
	
    /**
     * 将每行的值压入堆栈
     *
     * @access public
     * @param array $value 每行的值
     * @return array
     */
    public function filter(array $value) : array
    {
		if (isset($value['mid'])) {	
            $value['directory'] = $this->getParentsAlias($value['mid']);

            $tmpCategoryTree = $value['directory'];
            $value['directory'] = implode('/', array_map('urlencode', $value['directory']));

            $value = parent::filter($value);
            $value['directory'] = $tmpCategoryTree;
		}

        return $value;
    }
}

